3
3
.
.
1
1
.
.
7
7
@
@
E
E
n
n
v
v
i
i
r
r
o
o
n
n
m
m
e
e
n
n
t
t
O
O
b
b
j
j
e
e
c
c
t
t
I
I
n
n
f
f
o
o
[
[
R
R
]
]
[
[
R
R
]
]
If Variable is declared as @EnvironmentObject then SwiftUI will try to find an Instance with this name in Environment.
If Instance with such name exists in Environment then
if it is a Class Instance SWiftIU will populate this Variable with a reference to that Class Instance
if it is a Struct Instance SWiftIU will populate this Variable with a copy of that Struct Instance
This way data doesn't need to be sent to each View as a parameter when View is added to Hierarchy.
Instead each Views can have direct access to that data directly from the Environment.
Such Instance can be created inside SceneDelegate.swift as highlighted in yellow.
In this example we are creating single instance of User Class and storing it into Environment.
To store multiple Instances of different Classes or structs simply chain the calls as shown below.
Store multiple Instances
let contentView = ContentView()
.environmentObject(firstBindable)
.environmentObject(secondBindable)
E
E
x
x
a
a
m
m
p
p
l
l
e
e
In this example we create person Instance inside the ContentView.
Then we put that Instance in Environment as we call DetailView() without Parameters.
ContentView.swift
import SwiftUI
//==========================================================================
// Person
//==========================================================================
class Person : ObservableObject { //Must conform to ObservableObject Protocol
var name = "John" //Otherwise you can't use @EnvironmentObject
}
//==========================================================================
// ContentView
//==========================================================================
struct ContentView: View {
var person = Person() //Create person Instance
var body: some View {
DetailView().environmentObject(person) //Put person Instance into Environment
}
}
//==========================================================================
// DetailView
//==========================================================================
struct DetailView : View {
@EnvironmentObject var person : Person //Get person Instance from Environment
var body : some View {
Text(person.name)
}
}
C
C
r
r
e
e
a
a
t
t
e
e
E
E
n
n
v
v
i
i
r
r
o
o
n
n
m
m
e
e
n
n
t
t
O
O
b
b
j
j
e
e
c
c
t
t
i
i
n
n
S
S
c
c
e
e
n
n
e
e
D
D
e
e
l
l
e
e
g
g
a
a
t
t
e
e
.
.
s
s
w
w
i
i
f
f
t
t
In this example in the File SceneDelegate.swif we create user Instance and put it inside the Environment.
We also define User Class in a separate File User.swift.
User.swift (Create)
import SwiftUI
class User : ObservableObject {
@Published var userName : String
@Published var password : String
@Published var emailAddress : String
init(userName: String, password: String, emailAddress: String) {
self.userName = userName
self.password = password
self.emailAddress = emailAddress
}
}
SceneDelegate.swift (Update)
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var user = User(userName: "John", password: "mypassword", emailAddress: "john@gmail.com")
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions:
UIScene.ConnectionOptions) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView().environmentObject(user)
Store multiple Instances
let contentView = ContentView()
.environmentObject(firstBindable)
.environmentObject(secondBindable)
U
U
s
s
e
e
E
E
n
n
v
v
i
i
r
r
o
o
n
n
m
m
e
e
n
n
t
t
O
O
b
b
j
j
e
e
c
c
t
t
In this example we use Environment Object that as created in previous example.
This example demonstrates how @EnvironmentObject behaves the same as using @ObservedObject.
Changes to Class Instance are propagated to all parts of the Views which are then redrawn accordingly with new values.
ContentView.swift
import SwiftUI
struct ContentView : View {
@EnvironmentObject var user : User
var body:some View {
VStack {
TextField("Enter Username" , text: $user.userName ).padding()
TextField("Enter Password" , text: $user.password ).padding()
TextField("Enter Email Address", text: $user.emailAddress).padding()
Text(user.userName) //Detects changes in the Object & redraws View
}
}
}
Initial Screen Entered Value is propagated to other Views
U
U
s
s
e
e
E
E
n
n
v
v
i
i
r
r
o
o
n
n
m
m
e
e
n
n
t
t
O
O
b
b
j
j
e
e
c
c
t
t
-
-
I
I
n
n
m
m
u
u
l
l
t
t
i
i
p
p
l
l
e
e
V
V
i
i
e
e
w
w
s
s
This example demonstrates how @EnvironmentObject behaves the same as using @ObservedObject.
Changes to the Class Instance are propagated to all Views which are then redrawn accordingly with new values.
ContentView.swift
import SwiftUI
//==========================================================================
// ContentView
//==========================================================================
struct ContentView : View {
var body:some View {
HStack(spacing: 20) {
LoginView1().border(Color.red , width: 3)
LoginView2().border(Color.blue, width: 3)
}
}
}
//==========================================================================
// LoginView1
//==========================================================================
struct LoginView1 : View {
@EnvironmentObject var user : User
var body : some View {
VStack {
TextField("Enter Username" , text: $user.userName ).padding()
TextField("Enter Password" , text: $user.password ).padding()
TextField("Enter Email Address", text: $user.emailAddress).padding()
}
}
}
//==========================================================================
// LoginView2
//==========================================================================
struct LoginView2 : View {
@EnvironmentObject var user : User
var body : some View {
VStack {
TextField("Enter Username" , text: $user.userName ).padding()
TextField("Enter Password" , text: $user.password ).padding()
TextField("Enter Email Address", text: $user.emailAddress).padding()
}
}
}
Both Views hold reference to the same Class Instance Changes in are reflected in the other View as we type